﻿using System;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Web;
using EzDesk.Utility.Log;
using System.Threading;

namespace EzDesk.Utility.Web.ServiceReference
{
    public static class ServiceReferenceFactory<TServiceInterface, TServiceProxy>
        where TServiceProxy : ClientBase<TServiceInterface>, TServiceInterface, new()
        where TServiceInterface : class
    {
        private static TServiceInterface _instance = null;
        private static readonly object LockHelper = new object();
        private static int rebuildInstanceCount = 0; // 实例重建计数
        private static TimeSpan _instanceLifeTime = TimeSpan.FromHours(1);
        private static Timer _timer;

        public static TServiceInterface GetService()
        {
            tryRebuildInstance();
            return _instance;
        }


        private static TServiceInterface initializeNewInstance()
        {
            _timer = new Timer(rebuildInstanceCallback, null, _instanceLifeTime, TimeSpan.Zero);
            var client = new TServiceProxy();
            client.InnerChannel.Faulted += InnerChannel_Faulted;
            return client;
        }

        private static void rebuildInstanceCallback(object state)
        {
            rebuildInstance();
        }

        private static void rebuildInstance()
        {
            _instance = null;

            // 短时间内多次重建失败则停止重建
            if (++rebuildInstanceCount < 10)
            {
                LogEx.TRACE("ServiceReferenceFactory", "rebuildInstanceCount: " + rebuildInstanceCount + typeof(TServiceProxy).FullName);
                tryRebuildInstance();
            }
        }

        private static void InnerChannel_Faulted(object sender, EventArgs e)
        {
            rebuildInstance();
        }

        public static TServiceInterface GetServiceWithUseragentStr(string userAgent)
        {
            tryRebuildInstance();

            var client = (TServiceProxy)_instance;

            var serviceOperationContextScope = new OperationContextScope(client.InnerChannel);

            if (WebOperationContext.Current != null)
            {
                var messageProperty = WebOperationContext.Current.OutgoingRequest;

                // todoL reflactor the UserAgent String
                messageProperty.Headers.Add(HttpRequestHeader.UserAgent, "EzDesk,GenericcMobile");
            }
            return client;
        }

        private static void tryRebuildInstance()
        {
            if (_instance == null)
            {
                lock (LockHelper)
                {
                    if (_instance == null)
                    {
                        var temp = initializeNewInstance();
                        _instance = temp;
                        // 重建成功，恢复重建次数
                        rebuildInstanceCount = 0;
                    }
                }
            }
        }
    }
}
